
//
// 120308 - AH - Created.
// 120315 - AH - Renamed from SoekratHttpServlet.
// 120329 - AH - Engine is now connected and process single line input. What
//               reminds is proper client response of what is retrieved.
// 120409a- AH - Fixed so input passed on the ConcersationElement so input
//               actually passed to engine!
// 120409b- AH - Removed fake response code.
// 120618 - AH - (Aura) Handles that may not find ConversationElement given the
//               key in client's request.
// 120626 - AH - (Huset) Took VISITOR_NAME, CE_ID and CHAT in use.
//

package org.soekrat.server.servlets.chat;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.japril.servlet.HttpRequestDef;
import org.japril.servlet.HttpRequestParameter;
import org.soekrat.engine.LineCaptor;
import org.soekrat.engine.Soekrat2Engine;
import org.soekrat.engine.SoekratEngine;
import org.soekrat.engine.captor.Captor;
import org.soekrat.engine.sparewheel.SpareWheel;
import org.soekrat.environment.Orb;
import org.soekrat.environment.OrbSuppliers;
import org.soekrat.environment.conversationbase.SoekratDatabase;
import org.soekrat.server.io.db.ConversationElement;
import org.soekrat.server.io.db.SoekratDAO;
import org.soekrat.server.io.db.SoekratDAOFactory;
import org.soekrat.server.orbsuppliers.s2.ChatOutputFactory;
import org.soekrat.server.serialization.ChatOutputSerializable;
import org.soekrat.server.serialization.ConversationElementSerializable;
import org.soekrat.server.serialization.SoekratChatResponseSerializable;
import org.soekrat.server.serialization.VisitorAccountSerializable;
import org.soekrat.server.servlets.AbstractSoekratHttpServlet;

/**
 * <p>
 *   Soekrat HTTP servlet.
 * </p>
 * @author Arne Halvorsen (AH)
 */
@SuppressWarnings("serial")
public final class TextHttpServlet extends AbstractSoekratHttpServlet 
  //implements Sensor
{
  private String m_sensed=null;
  
  private List<Captor> m_captors=new ArrayList<Captor>();
  
  /**
   * <p>
   *   Constructor.
   * </p>
   */
  public TextHttpServlet(){}
  
  @Override
  protected void handleRequest(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
  { 
    HttpRequestDef def=getHttpRequestDef();
    
    if (!hasParameters(req))
    {
      PrintWriter pw=printSimpleHtmlStart(res);
      pw.println(def.compileApiHtml());
      printSimpleHtmlEnd(pw);
    }
    else
    {     
      if (!validate(res, def, req)) return;
      
      String visitor=def.fetch(VISITOR_NAME.name(), req).getStringValue();
      
      Long ceId=def.fetch(CE_ID.name(), req).getLongValue();
      
      m_sensed=def.fetch(CHAT.name(), req).getStringValue();
      m_sensed=(m_sensed==null) ? "" : m_sensed.trim();
      
      SoekratDAO dao=new SoekratDAOFactory().create();
      
      Orb orb=new Orb();
      
      ///
      
      LineCaptor.createLinesToOrbS2(m_sensed, orb);
      
      ///
      
      if (ceId!=null) orb.setAttribute("ce-id", ceId);
      orb.setAttribute("visitor", visitor);
      orb.setAttribute("sensor", this);
      
      OrbSuppliers suppliers=getOrbSuppliers();
      String err=suppliers.supply(orb);
      if (err!=null)
      {
        respond(res, err);
        return;
      }
      
      ConversationElement ce=(ConversationElement)orb.getAttribute(
        "conversation-element");
     
      dao.update(ce);
      
      SoekratEngine engine=(SoekratEngine)orb.getAttribute("soekrat-engine");
      if (engine==null)
      {
        respond(res, "No engine created");
        return;
      }
      
      //activateCaptors(orb);
      
      engine.consult(orb);
      
      ChatOutputFactory cof=
        (ChatOutputFactory)orb.getAttribute("chatoutput-factory");
      if (cof==null)
      {
        respond(res, "No chatouput factory created");
        return;
      }
      
      ChatOutputSerializable cos=cof.process(orb, visitor, ce.id());
      
      SoekratChatResponseSerializable sr=new SoekratChatResponseSerializable();
      sr.account(new VisitorAccountSerializable(visitor));
      sr.ce(new ConversationElementSerializable(ce.id()));
      sr.chatOutput(cos);
      
      save(orb);
        
      respond(res, sr);
    }
  }
  
  @SuppressWarnings("unused")
  private void activateCaptors(Orb orb)
  {
    for (Captor c : m_captors)
    {
      System.out.println("Activates captor: "+c.getClass().getName());
      //Object r=c.capturing(this, orb);
      //c.capturing(this, orb);
      
      
      String name=c.getProducedDataName();
      System.out.println("Name on data produced: "+name);
      //System.out.println("Data type produced: "+r.getClass().getName());
      
      //orb.setAttribute(name, r);
    }
  }
  
  // Specified in Sensor.
  public void addCaptor(Captor c)
  {
    if (c==null)
    {
      throw new NullPointerException("c");
    }
    
    if (!m_captors.contains(c)) m_captors.add(c);
  }

  // Specified in Sensor.
  public Object getData(){ return m_sensed; } 
 
  // Specified in Sensor.
  public String getSensedDataType() { return "text"; }
  
  private void save(Orb orb)
  {
    if (orb==null)
    {
      throw new NullPointerException("orb");
    }
    
    Soekrat2Engine engine=(Soekrat2Engine)orb.getAttribute("soekrat-engine");
    SoekratDatabase sd=(SoekratDatabase)orb.getAttribute("database");
   
    if (engine!=null && sd!=null)
    {
      SpareWheel sw=engine.getSpareWheel();
      if (sw!=null)
      {
        try
        {
          sd.save(sw);
        }
        catch (IOException iox)
        {
          
        }
      }
    }
  }
  
  
  
  /*
  // Moved
  private ConversationElement getConversationElement(SoekratDAO dao, Long ceId, 
    String user)
  {
    ConversationElement ce=(ceId==null) ? null : 
                                          dao.getConversationElement(ceId);
    
    Map<String, String> params=new HashMap<String, String>();
    params.put("engine", "soekrat2");
    if (ce==null)
    {
      Account account=getAccount(dao, user);
      ce=dao.createConversationElement(account, params);
      createDefSemanticEffects(dao, ce);
      
      Folder rb=getRatbase();
      if (rb!=null)
      {
        ce.setParameter("rat-base-id", Long.toString(rb.id()));
      }
    }
    
    return ce;
  }
  */
  
  // Moved
  /*
  private Account getAccount(SoekratDAO dao, String name)
  {
    Account retVal=dao.getAccount(name);
    
    if (retVal==null) retVal=dao.createAccount(name);
    
    return retVal;
  }
  */
  
  // Moved
  /*
  @SuppressWarnings("unused")
  private void createDefSemanticEffects(SoekratDAO dao, ConversationElement ce)
  {
    String name="echo";
    String action="hear";
    SemanticEffect se=dao.createSemanticEffect(ce, name, action);  
  }
  */
  
  /*
  private void readMultiLines(ConversationElement ce, String chat)
    throws IOException
  {
    ce.begin();
    
    CharArrayReader car=new CharArrayReader(chat.toCharArray());
    BufferedReader br=new BufferedReader(car);
    String line=br.readLine();
    while (line!=null)
    {
      line=line.trim();
      if (line.length()!=0)
      {
        ce.addChatInputLine(line);
      }
      line=br.readLine();
    }
  }
  */
  
  // Moved
  /*
  private Folder getRatbase()
  {
    SoekratDAO dao=new SoekratDAOFactory().create();
    List<Folder> bases=dao.getRatBases();
    if (bases.isEmpty()) return null;
    Collections.shuffle(bases);
    return bases.get(0);
  }
  */
  
  @Override
  public HttpRequestDef getHttpRequestDef() 
  {
    return new HttpRequestDef("/soekrat_server/soekrat")
      .desc("Chat").parameter(VISITOR_NAME)
      .parameter(new HttpRequestParameter(CE_ID).mandatory(false))
      .parameter(CHAT);
  }
  
}
